<?php


namespace crack9527\utils\lang;


use crack9527\utils\exception\TextException;

/**
 * Class Text
 * @package crack9527\utils\lang
 */
class Text
{
    /**
     * @var
     */
    private $value;

    private $_isDebug;

    private $_debugData;

    /**
     * Text constructor.
     * @param $value
     */
    public function __construct($value)
    {
        $this->value = $value;
    }

    /**
     * @return mixed
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * @param mixed $value
     */
    public function setValue($value): void
    {
        if ($this->getIsDebug()) {
            $data = debug_backtrace();
            $this->_debugData[] = $data[1]['function'] . ' => ' . $value;
        }
        $this->value = $value;
    }

    /**
     * @return mixed
     */
    public function getIsDebug()
    {
        return $this->_isDebug;
    }

    /**
     * @param mixed $debug
     * @return $this
     */
    public function setIsDebug($debug)
    {
        $this->_isDebug = $debug;
        return $this;
    }

    /**
     * @return mixed
     */
    public function __toString()
    {
        return $this->toString();
    }

    public function toString()
    {
        return $this->getIsDebug() ? $this->_debugData : $this->value;
    }

    /**
     *  以 C 语言风格使用反斜线转义字符串中的字符
     * @param null $charlist
     * 如果 charlist 中包含有 \n，\r 等字符，将以 C 语言风格转换，而其它非字母数字且 ASCII 码低于 32 以及高于 126 的字符均转换成使用八进制表示。
     * 当定义 charlist 参数中的字符序列时，需要确实知道介于自己设置的开始及结束范围之内的都是些什么字符。
     * @return $this
     */
    public function addCSlashes($charlist = null)
    {
        $this->setValue(addcslashes($this->value, $charlist));
        return $this;
    }

    /**
     * 增加反斜线转义
     * @return $this
     */
    public function addSlashes()
    {
        $this->setValue(addslashes($this->value));
        return $this;
    }

    /**
     * 去除反斜线转义
     * @return $this
     */
    public function stripSlashes()
    {
        $this->setValue(stripslashes($this->value));
        return $this;
    }

    /**
     * 包含数据的二进制字符串转换为十六进制值
     * @return $this
     */
    public function bin2hex()
    {
        $this->setValue(bin2hex($this->value));
        return $this;
    }

    /**
     * 将字符串分割成小块,它会在每 chunklen 个字符后边插入 end
     * @param int $chunkLen 分割的尺寸
     * @param string $end 行尾序列符号
     * @return $this
     */
    public function chunkSplit($chunkLen = 76, $end = "\r\n")
    {
        $this->setValue(chunk_split($this->value, $chunkLen, $end));
        return $this;
    }

    /**
     *  计算一个字符串的 crc32 多项式
     * @return $this
     */
    public function crc32()
    {
        $this->setValue(sprintf('%u', crc32($this->value)));
        return $this;
    }

    /**
     * 单向字符串散列
     * @param string $salt
     * @return $this
     */
    public function crypt($salt = '')
    {
        $this->setValue(crypt($this->value, $salt));
        return $this;
    }

    /**
     * 使用一个字符串分割另一个字符串
     * @param string $delimiter 边界上的分隔字符
     * @param int $limit 如果设置了 limit 参数并且是正数，则返回的数组包含最多 limit 个元素，而最后那个元素将包含 string 的剩余部分。
     * @return array
     */
    public function explode($delimiter)
    {
        if (func_num_args() == 2) {
            return explode($delimiter, $this->value, func_get_arg(1));
        }
        return explode($delimiter, $this->value);
    }

    /**
     * 转换十六进制字符串为二进制字符串
     * @return $this
     */
    public function hex2bin()
    {
        $this->setValue(hex2bin($this->value));
        return $this;
    }

    /**
     * 将HTML转义字符还原
     * @param int $flags
     * @param $encoding
     * @return $this
     */
    public function htmlEntityDecode($flags = ENT_HTML401 | ENT_COMPAT, $encoding = '')
    {
        $this->setValue('' !== $encoding ? html_entity_decode($this->value, $flags, $encoding) : html_entity_decode($this->value, $flags));
        return $this;
    }

    /**
     * 将字符转换为 HTML 转义字符
     * @param int $flags
     * @param string $encoding
     * @return $this
     */
    public function htmlEntityEncode($flags = ENT_HTML401 | ENT_COMPAT, $encoding = '')
    {
        $this->setValue('' !== $encoding ? htmlentities($this->value, $flags, $encoding) : htmlentities($this->value, $flags));
        return $this;
    }

    /**
     * 将普通字符转换特殊的HTML实体
     * @param int $flags
     * @return $this
     */
    public function htmlSpecialCharsEncode($flags = ENT_COMPAT | ENT_HTML401)
    {
        $this->setValue(htmlspecialchars($this->value, $flags));
        return $this;
    }

    /**
     * 将特殊的 HTML 实体转换回普通字符
     * @param int $flags
     * @return $this
     */
    public function htmlSpecialCharsDecode($flags = ENT_COMPAT | ENT_HTML401)
    {
        $this->setValue(htmlspecialchars_decode($this->value, $flags));
        return $this;
    }

    /**
     * 使第一个字符小写
     * @return $this
     */
    public function lcFirst()
    {
        $this->setValue(lcfirst($this->value));
        return $this;
    }

    /**
     * 指定想要删除的字符
     * @param string ...$characterMask
     * @return $this
     */
    public function ltrim(...$characterMask)
    {
        $this->setValue($characterMask ? ltrim($this->value, $characterMask[0]) : ltrim($this->value));
        return $this;
    }

    /**
     * 删除字符串末端的空白字符（或者其他字符）
     * @param string ...$characterMask
     * @return $this
     */
    public function rtrim(...$characterMask)
    {
        $this->setValue($characterMask ? rtrim($this->value, $characterMask[0]) : rtrim($this->value));
        return $this;
    }

    /**
     * 在字符串所有新行之前插入 HTML 换行标记
     * @return $this
     */
    public function nl2br()
    {
        $this->setValue(nl2br($this->value));
        return $this;
    }

    /**
     * 将字符串解析成多个变量
     * @param $array
     * @return $this
     */
    public function parseString(&$array)
    {
        parse_str($this->value, $array);
        return $this;
    }

    /**
     * 转义元字符集
     * 在下面这些特殊字符前加 反斜线(\) 转义后的字符串。这些特殊字符包含： * . \ + * ? [ ^ ] ( $ )
     * @return $this
     */
    public function quoteMeta()
    {
        $this->setValue(quotemeta($this->value));
        return $this;
    }

    /**
     * 计算字符串的 sha1 散列值
     * @param bool $rawOutput 如果可选的 raw_output 参数被设置为 TRUE，那么 sha1 摘要将以 20 字符长度的原始格式返回，否则返回值是一个 40 字符长度的十六进制数字
     * @return $this
     */
    public function sha1($rawOutput = false)
    {
        $this->setValue(sha1($this->value, $rawOutput));
        return $this;
    }

    /**
     * 以 CSV 字段格式解析字符串输入，并返回包含读取字段的数组。
     * @param string $delimiter
     * @param string $enclosure
     * @param string $escape
     * @return array
     */
    public function getCsv($delimiter = ',', $enclosure = '"', $escape = '\\')
    {
        return str_getcsv($this->value, $delimiter, $enclosure, $escape);
    }

    /**
     * 替换字符串
     * @param $search
     * @param $replace
     * @param array $args
     * @return $this
     */
    public function replace($search, $replace, ...$args)
    {
        if ($args) {
            $this->setValue(str_replace($search, $replace, $this->value, $args[0]));
            return $this;
        }
        $this->setValue(str_replace($search, $replace, $this->value));
        return $this;
    }

    /**
     * 替换字符串(忽略大小写)
     * @param $search
     * @param $replace
     * @param mixed ...$args
     * @return $this
     */
    public function replaceIgnoreCase($search, $replace, ...$args)
    {
        if ($args) {
            $this->setValue(str_ireplace($search, $replace, $this->value, $args[0]));
            return $this;
        }
        $this->setValue(str_ireplace($search, $replace, $this->value));
        return $this;
    }

    /**
     * 替换字符串,只替换1次
     * @param $search
     * @param $replace
     * @return $this
     */
    public function replaceFirst($search, $replace)
    {
        return $this->replace($search, $replace, 1);
    }

    /**
     * 替换字符串,只替换1次(忽略大小写)
     * @param $search
     * @param $replace
     * @return $this
     */
    public function replaceFirstIgnoreCase($search, $replace)
    {
        $this->setValue(str_ireplace($search, $replace, $this->value, 1));
        return $this;
    }

    /**
     * 使用另一个字符串填充字符串为指定长度
     * @param int $padLength 如果 pad_length 的值是负数，小于或者等于输入字符串的长度，不会发生任何填充。
     * @param string $padString
     * @param int $padType
     * @return $this
     */
    public function pad($padLength, $padString = ' ', $padType = STR_PAD_RIGHT)
    {
        $this->setValue(str_pad($this->value, $padLength, $padString, $padType));
        return $this;
    }

    /**
     * @param int $multiplier 必须大于等于 0。如果 multiplier 被设置为 0，函数返回空字符串
     * @return $this
     * @throws TextException
     */
    public function repeat($multiplier)
    {
        if ($multiplier <= 0) {
            throw new TextException('重复数量必须大于0');
        }
        $this->setValue(str_repeat($this->value, $multiplier));
        return $this;
    }

    /**
     * 随机打乱
     * @return $this
     */
    public function shuffle()
    {
        $this->setValue(str_shuffle($this->value));
        return $this;
    }

    /**
     * 将一个字符串转换为数组
     * @param int $splitLength 每一段的长度
     * @return array
     */
    public function split($splitLength = 1)
    {
        return str_split($this->value, $splitLength);
    }

    /**
     * 从字符串中去除 HTML 和 PHP 标记
     * @param string $allowableTags 指定不被去除的字符列表
     * @return $this
     */
    public function stripTags($allowableTags = '')
    {
        $this->setValue(strip_tags($this->value, $allowableTags));
        return $this;
    }

    /**
     * 返回反转义后的字符串。可识别类似 C 语言的 \n，\r，... 八进制以及十六进制的描述
     * @return $this
     */
    public function stripCSlashes()
    {
        $this->setValue(stripcslashes($this->value));
        return $this;
    }

    /**
     * 查找字符串首次出现的位置(区分大小写)
     * @param string $search
     * @param int $offset
     * @return int 字符串位置,起始于 0
     */
    public function indexOf($search = '', $offset = 0)
    {
        return strpos($this->value, $search, $offset);
    }

    /**
     * 查找在目标字符串中最后一次出现的位置(区分大小写)
     * @param string $search
     * @param int $offset
     * @return bool|int
     */
    public function lastIndexOf($search = '', $offset = 0)
    {
        return strrpos($this->value, $search, $offset);
    }

    /**
     * 找字符串首次出现的位置（不区分大小写）
     * @param string $search
     * @param int $offset
     * @return int
     */
    public function indexOfIgnoreCase($search = '', $offset = 0)
    {
        return stripos($this->value, $search, $offset);
    }

    /**
     * 查找在目标字符串中最后一次出现的位置(不区分大小写)
     * @param string $search
     * @param int $offset
     * @return bool|int
     */
    public function lastIndexOfIgnoreCase($search = '', $offset = 0)
    {
        return strrpos($this->value, $search, $offset);
    }

    /**
     * 裁剪文本之前的部分(区分大小写)
     * @param string $search 匹配文本
     * @return $this
     */
    public function substringBefore($search)
    {
        $this->setValue(strstr($this->value, $search, true));
        return $this;
    }

    /**
     * 裁剪文本之前的部分(忽略大小写)
     * @param string $search 匹配文本
     * @return $this
     */
    public function substringBeforeIgnoreCase($search)
    {
        $this->setValue(stristr($this->value, $search, true));
        return $this;
    }

    /**
     * 裁剪文本之后的部分(区分大小写)
     * @param string $search 匹配文本
     * @return $this
     */
    public function substringAfter($search)
    {
        $value = strstr($this->value, $search, false);
        if (false === $value) {
            $this->setValue('');
            return $this;
        }
        return $this->substring(1);
    }

    /**
     * 裁剪文本之后的部分(忽略大小写)
     * @param $search
     * @return $this|Text
     */
    public function substringAfterIgnoreCase($search)
    {
        $value = stristr($this->value, $search, false);
        if (false === $value) {
            $this->setValue('');
            return $this;
        }
        return $this->substring(1);
    }

    /**
     *  获取字符串长度
     * @return int
     */
    public function length()
    {
        return strlen($this->value);
    }

    /**
     * 将字符串转化为小写
     * @return $this
     */
    public function toLowerCase()
    {
        $this->setValue(strtolower($this->value));
        return $this;
    }

    /**
     * 将字符串转化为大写
     * @return $this
     */
    public function toUpperCase()
    {
        $this->setValue(strtoupper($this->value));
        return $this;
    }

    /**
     * 返回字符串的子串
     * @param int $start 开始位置，从 0 开始计算
     * @param int $length 指定长度
     * @return $this
     */
    public function substring($start = 0, $length = -1)
    {
        if ($length > 0) {
            $this->setValue(substr($this->value, $start, $length));
            return $this;
        }
        $this->setValue(substr($this->value, $start));
        return $this;
    }

    /**
     * 去除字符串首尾处的空白字符（或者其他字符）
     * @param string $charlist
     * @return $this
     */
    public function trim($charlist = '\t\n\r\0\x0B')
    {
        $this->setValue(trim($this->value, $charlist));
        return $this;
    }

    /**
     * 将字符串的首字母转换为大写
     * @return $this
     */
    public function ucFirst()
    {
        $this->setValue(ucfirst($this->value));
        return $this;
    }

    /**
     * 将字符串中每个单词的首字母转换为大写
     * @return $this
     */
    public function ucWords()
    {
        $this->setValue(ucwords($this->value));
        return $this;
    }

    /**
     * 打断字符串为指定数量的字串
     * @param int $width 列宽度
     * @param string $break 使用可选的 break 参数打断字符串
     * @param bool $cut 如果 cut 设置为 TRUE，字符串总是在指定的宽度或者之前位置被打断。因此，如果有的单词宽度超过了给定的宽度，它将被分隔开来
     * @return $this
     */
    public function wordwrap($width = 75, $break = "\n", $cut = false)
    {
        $this->setValue(wordwrap($this->value, $width, $break, $cut));
        return $this;
    }

    /**
     * 判断是否为指定字符开头
     * @param string $prefix
     * @return bool
     */
    public function startsWith($prefix = '')
    {
        return substr(0, strlen($prefix)) === $prefix;
    }

    /**
     * 判断是否为指定字符结尾
     * @param string $prefix
     * @return bool
     */
    public function endsWith($prefix = '')
    {
        return substr($this->value, -strlen($prefix)) === $prefix;
    }

    /**
     * 判断字符串是否为空
     * @return bool
     */
    public function isEmpty()
    {
        return StringUtils::isEmpty($this->value);
    }

    /**
     * 计算md5
     * @return $this
     */
    public function md5()
    {
        $this->setValue(md5($this->value));
        return $this;
    }

    /**
     * 插入字符串
     * @param int $start
     * @param string $string
     * @return $this
     */
    public function insert($start, $string)
    {
        $before = substr($this->value, 0, $start);
        $after = substr($this->value, -$start);
        $this->setValue($before . $string . $after);
        return $this;
    }
}